#!/usr/bin/env python3
import sys
import os
import shutil
from xml.etree.ElementTree import Element
from xml.etree import ElementTree as ET
from dealres import ResDealer, writetofile
import yaml

axmlns = {'android': 'http://schemas.android.com/apk/res/android'}
ET.register_namespace('android', 'http://schemas.android.com/apk/res/android')

def copyfileWrapper(src, dst):
    dir = os.path.dirname(dst)
    if not os.path.exists(dir):
        os.makedirs(dir)
    if os.path.exists(dst):
        print('{} file exist!!!'.format(dst))
        sys.exit(0)
    shutil.copyfile(src, dst)


def copy_dir(srcdir,newdir, overwrite):
    if not os.path.exists(newdir):
        os.makedirs(newdir)
    for p in os.listdir(srcdir):
        filepath=newdir+'/'+p
        oldpath=srcdir+'/'+p
        if os.path.isdir(oldpath):
            os.mkdir(filepath)
            copy_dir(oldpath,filepath, overwrite)
        elif os.path.isfile(oldpath):
            if os.path.exists(filepath) and not overwrite:
                print('{} file exist!!!'.format(filepath))
                sys.exit(0)
            else:
                shutil.copyfile(oldpath, filepath)


def mergeAssets(src, dst, overwrite):
    srcassets = src + '/assets/'
    dstassets = dst + '/assets/'
    if os.path.exists(srcassets):
        copy_dir(srcassets, dstassets, overwrite)


def mergeLib(src, dst, overwrite):
    srclibdir = src + '/lib/'
    dstlibdir = dst + '/lib/'
    if os.path.exists(srclibdir):
        if os.path.exists(dstlibdir):
            for eabidir in os.listdir(dstlibdir):
                copy_dir(srclibdir + eabidir, dstlibdir + eabidir, overwrite)
        else:
            copy_dir(srclibdir + "armeabi-v7a/", dstlibdir + "armeabi-v7a", overwrite)



def mergeresxml(srcfile, dstfile):
    print('{}-->{}'.format(srcfile, dstfile))
    if os.path.exists(dstfile):
        srcTree = ET.parse(srcfile)
        dstTree = ET.parse(dstfile)

        dstroot = dstTree.getroot()
        for i in list(srcTree.getroot()):
            skip = False
            for j in  dstroot.findall(i.tag):
                if i.attrib["name"] == j.attrib["name"]:
                    print('\tskip:{}'.format(i.attrib['name']))
                    skip = True
                    break
            if not skip:
                dstroot.append(i)
        dstTree.write(dstfile,encoding="utf-8", xml_declaration=True)
    else:
        shutil.copyfile(srcfile, dstfile)


def copy_dir_resxml(srcdir, newdir, overwrite):
    if not os.path.exists(newdir):
        os.makedirs(newdir)
    for p in os.listdir(srcdir):
        filepath=newdir+'/'+p
        oldpath=srcdir+'/'+p
        if os.path.isdir(oldpath):
            os.mkdir(filepath)
            copy_dir_resxml(oldpath,filepath, overwrite)
        elif os.path.isfile(oldpath):
            if os.path.exists(filepath) and not overwrite:
                if filepath.endswith('.xml'):
                    print('{} mergexml'.format(filepath))
                    mergeresxml(oldpath, filepath)
                else:
                    print('{} file exist!'.format(filepath))
                    sys.exit(-1)
            else:
                shutil.copyfile(oldpath, filepath)


def mergeRes(src, dst, overwrite):
    srcres = src + '/res/'
    dstres = dst + '/res/'
    for restype in os.listdir(srcres):
        if restype.startswith('values'):
            print('deal with res values')
            srcvaluedir = srcres + restype
            dstvaluedir = dstres + restype
            if not os.path.exists(dstvaluedir):
                os.mkdir(dstvaluedir)
            for valuefile in os.listdir(srcvaluedir): #便利values目录
                if valuefile == 'public.xml':
                    continue
                else:
                    mergeresxml(srcvaluedir + '/' + valuefile, dstvaluedir + '/' + valuefile)
        else:
            copy_dir_resxml(srcres + restype, dstres + restype, overwrite)


def mergeSmali(src, dst):
    print('mergeSmali begin:')
    lastsmalidir = 1
    for f in os.listdir(dst):
        if f.startswith('smali_classes'):
            lastsmalidir = int(f[13:]) if int(f[13:]) > lastsmalidir else lastsmalidir
    lastsmalidir+=1
    dstdir = dst + '/smali_classes%d'%(lastsmalidir)
    print(dstdir)
    srcdir = src + '/smali'
    copy_dir(srcdir, dstdir, True)


def mergeapplication(srcapp:Element, dstroot:Element, srcpkgname, dstpkgname:str):
    dstapp = dstroot.find("application")
    getMainActivity(dstapp)
    nameattr = "{%s}name"%(axmlns['android'])
    if nameattr in dstapp.attrib:
        print("dstentry Application Class Name: \033[31m{}\033[0m".format(dstapp.get(nameattr, '')))
    else:
        print('set appname to:' + entryAppName)
        dstapp.attrib[nameattr] = entryAppName
    usesCleartextTraffic = '{%s}usesCleartextTraffic'%(axmlns['android'])
    if dstapp.attrib.get(usesCleartextTraffic, 'false') == 'false':
        dstapp.attrib[usesCleartextTraffic] = 'true'

    for provider in srcapp.findall('provider'):
        authorities = '{%s}authorities'%(axmlns['android'])
        provider.attrib[authorities] = provider.attrib[authorities].replace(srcpkgname, dstpkgname)
    for ele in srcapp:
        skip = False
        for j in  dstapp.findall(ele.tag):
            if ele.attrib[nameattr] == j.attrib[nameattr] or ele.attrib[nameattr] == 'hzzy.AdUtils.MainActivity' or ele.attrib[nameattr] == 'hzzy.AdUtils.FakeAppActivity':
                print('\tskip:{}'.format(ele.attrib[nameattr]))
                skip = True
                break
        if not skip:
            dstapp.append(ele)


def getMainActivity(applicationroot:Element):
    nameattr = "{%s}name"%(axmlns['android'])
    for j in applicationroot.findall('activity'):
        intentfilter = j.find('intent-filter')
        if intentfilter:
            category = intentfilter.find('category')
            if category and category[nameattr] == 'android.intent.category.LAUNCHER':
                print('MainActivity:  {}'.format(j[nameattr]))


def mergeManifest(src, dst):
    print('mergeManifest begin:')
    srcmanifest = src + '/AndroidManifest.xml'
    dstmanifest = dst + '/AndroidManifest.xml'
    srcTree = ET.parse(srcmanifest)
    dstTree = ET.parse(dstmanifest)

    srcroot = srcTree.getroot()
    dstroot = dstTree.getroot()

    srcpkgname = srcroot.attrib['package']
    dstpkgname = dstroot.attrib['package']

    print('srcpkgname= {} -> dstpkgnam=\033[31m {}\033[0m'.format(srcpkgname, dstpkgname))
    for ele in list(srcroot):
        if ele.tag == 'application':
            mergeapplication(ele, dstroot, srcpkgname, dstpkgname)
        else:
            skip = False
            nameattr = "{%s}name"%(axmlns['android'])
            if nameattr in ele.attrib:
                for j in dstroot.findall(ele.tag):
                    if ele.attrib[nameattr] == j.attrib[nameattr]:
                        print('\tskip:{} {}'.format(ele.tag, ele.attrib[nameattr]))
                        skip = True
                        break
            if not skip:
                dstroot.append(ele)
    dstTree.write(dstmanifest,encoding="utf-8", xml_declaration=True)


def patchCert(dst):
    certname = ''
    certpath = ''
    rootdir = dst + '/original/META-INF/'
    if not os.path.exists(dst + '/assets/'):
        os.makedirs(dst + '/assets/')
    destpath = dst + '/assets/commonemoji.png'
    fs = os.listdir(rootdir)
    for f in fs:
        if f.endswith('.SF'):
            certname = f.split('.')[0]
            break
    for f in fs:
        if (not f.endswith('.SF')) and f.startswith(certname):
            certpath = rootdir + f
            break
    print(certpath)
    shutil.copy(certpath, destpath)


def patchVersion(dst):
    head = '!!brut.androlib.meta.MetaInfo\n'
    path = dst + '/apktool.yml'
    content = ''
    with open(path, 'r') as f:
        while True:
            l = f.readline()
            if not l:
                break
            if(l.startswith('!!')):
                continue
            content += l
    apktool = yaml.load(content, Loader=yaml.Loader)
    apktool['versionInfo']['versionCode'] = int(apktool['versionInfo']['versionCode']) + 1
    apktool['versionInfo']['versionName'] = str(apktool['versionInfo']['versionCode'])
    content = head
    content += yaml.dump(apktool)
    writetofile(path, content)


def doit(src, dst, overwrite):
    if True:
        ResDealer(src, dst).deal()
        dstpublicxml = dst + '/res/values/public.xml'
        shutil.copyfile(src + '/dst.xml', dstpublicxml)
    mergeRes(src, dst, overwrite)

    mergeAssets(src, dst, overwrite)
    mergeLib(src, dst, overwrite)

    mergeSmali(src, dst)
    mergeManifest(src, dst)

    patchCert(dst)

    patchVersion(dst)

    print("\nTODO:\ninsert start code in application")
    print('\tinvoke-static {p0}, Lhzzy/AdUtils/EntryApplication;->entry(Landroid/app/Application;)V\n')

    print("modify goto MainActivity")
    print("smali in do insert")



if __name__ == "__main__":
    _src = 'tmpadapp'
    _dst = sys.argv[2]
    entryAppName = 'hzzy.AdUtils.EntryApplication'
    if os.path.exists(_src):
        shutil.rmtree(_src)
    copy_dir(sys.argv[1], _src, False)
    _overwrite = False
    if len(sys.argv) == 4:
        _overwrite = sys.argv[3] == 'o'
    doit(_src, _dst, _overwrite)
    shutil.rmtree(_src)
